﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Utility.Math
{
	public static class MathEX
	{
		#region clamp
		public enum ClampType
		{
			Trim,
			Periodic,
			Pingpong,
		}

		public static float Clamp (this float value, float min, float max, ClampType clampType = ClampType.Trim)
		{
			switch (clampType)
			{
				case ClampType.Trim:
					return value > max ? max : value < min ? min : value;
				case ClampType.Periodic:
					var period = max - min;
					return (value % period + period) % period + min;
				case ClampType.Pingpong:
					value = Clamp (value, min, max * 2 - min, ClampType.Periodic);
					return value < max ? value : max * 2 - value;
				default:
					return value;
			}
		}

		public static float Clamp (this float value, Vector2 range, ClampType clampType = ClampType.Trim) => Clamp (value, range.x, range.y, clampType);

		public static int Clamp (this int value, int min, int max, ClampType clampType = ClampType.Trim)
		{
			switch (clampType)
			{
				case ClampType.Trim:
					return value > max ? max : value < min ? min : value;
				case ClampType.Periodic:
					var period = max - min;
					return (value % period + period) % period + min;
				case ClampType.Pingpong:
					value = Clamp (value, min, max * 2 - min, ClampType.Periodic);
					return value < max ? value : max * 2 - value;
				default:
					return value;
			}
		}

		public static int Clamp (this int value, Vector2Int range, ClampType clampType = ClampType.Trim) => Clamp (value, range.x, range.y, clampType);

		public static decimal Clamp (this decimal value, decimal min, decimal max, ClampType clampType = ClampType.Trim)
		{
			switch (clampType)
			{
				case ClampType.Trim:
					return value > max ? max : value < min ? min : value;
				case ClampType.Periodic:
					var period = max - min;
					return (value % period + period) % period + min;
				case ClampType.Pingpong:
					value = Clamp (value, min, max * 2 - min, ClampType.Periodic);
					return value < max ? value : max * 2 - value;
				default:
					return value;
			}
		}
		#endregion
		#region factorial
		public static long Factorial (this int value)
		{
			return Math.Factorial.Get (value);
		}
		#endregion
	}
}